package cn.demoncat.util.http;


import cn.demoncat.util.exception.RestRuntimeException;
import cn.demoncat.util.http.entity.HttpSslCertificateParam;
import cn.demoncat.util.io.CloseUtil;
import cn.demoncat.util.web.constant.HttpConstant;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import javax.net.ssl.*;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

/**
 * SSL证书工具
 * 
 * @author 延晓磊
 *
 * @since 2019年10月14日
 */
public class SslUtil {

    /**
     * 解析SSL证书
     * 
     * @param cert	SSL证书参数
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2019年10月14日
     */
    public static SSLConfig parse(HttpSslCertificateParam cert) {
    	SSLConfig sslConfig = new SSLConfig();
        try {
        	// 获取解钥管理器
            KeyManager[] keyManagers = createKeyManagers(cert.getPfxStream(), cert.getPfxPwd());
            // 获取信任证书
            X509TrustManager trustManager;
            if (cert.getTrustManager() != null) {
                // 优先使用自定义的TrustManager
                trustManager = cert.getTrustManager();
            } else {
                // 然后使用证书创建的TrustManager
                trustManager = createTrustManager(cert.getCertificates());
                if (trustManager == null) {
                	// 最后使用默认的TrustManager
                    trustManager = HttpConstant.DEFAULT_TRUST_MANAGER;
                }
            }
            // 创建TLS类型的SSLContext对象
            SSLContext sslContext = SSLContext.getInstance("TLS");
            // 使用TrustManager初始化SSLContext，这样SSLContext就会信任keyStore中的证书
            sslContext.init(keyManagers, new TrustManager[]{trustManager}, new SecureRandom());
            sslConfig.setSslSocketFactory(sslContext.getSocketFactory());
            sslConfig.setX509TrustManager(trustManager);
            return sslConfig;
        } catch (Exception e) {
        	throw new RestRuntimeException("解析SSL证书失败", e);
        }
    }

    /**
     * 根据服务端公钥证书生成信任证书
     * 
     * @param certificates	服务端公钥证书
     * @return
     * @throws Exception
     * 
     * @author 延晓磊
     *
     * @since 2019年10月14日
     */
    private static X509TrustManager createTrustManager(InputStream... certificates) throws Exception {
        if (ArrayUtils.isEmpty(certificates)) {
            return null;
        }
        // 创建证书工厂
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        // 创建默认的密钥仓库，存储信任的证书
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        // 开始处理证书
        for (int i = 0, length = certificates.length; i < length; i++) {
            // 将证书对象作为可信证书放入到keyStore中
            keyStore.setCertificateEntry(String.valueOf(i + 1), factory.generateCertificate(certificates[i]));
            CloseUtil.close(certificates[i]);
        }
        // 证书工厂
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        // 使用密钥仓库创建信任证书
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("创建证书信任管理器失败:" + ArrayUtils.toString(trustManagers));
        }
        return (X509TrustManager)trustManagers[0];
    }

    /**
     * 获取密钥管理器
     * 
     * @param pfxCertificate
     * @param pfxPassword
     * @return
     * @throws Exception
     * 
     * @author 延晓磊
     *
     * @since 2019年10月14日
     */
    private static KeyManager[] createKeyManagers(InputStream pfxCertificate, String pfxPassword) throws Exception{
        if (pfxCertificate == null || StringUtils.isBlank(pfxPassword)) {
            return null;
        }
        char[] pwd = pfxPassword.toCharArray();
        // 密钥仓库
        KeyStore clientKS = KeyStore.getInstance("PKCS12");
        clientKS.load(pfxCertificate, pwd);
        // 解密工厂
        KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        // 密钥管理器
        factory.init(clientKS, pwd);
        return factory.getKeyManagers();
    }

    /**
     * SSL证书配置
     * 
     * @author 延晓磊
     *
     * @since 2019年10月14日
     */
    public static final class SSLConfig {
    	// 证书工厂
        private SSLSocketFactory sslSocketFactory;
        // 证书管理器
        private X509TrustManager x509TrustManager;
        
		public SSLSocketFactory getSslSocketFactory() {
			return sslSocketFactory;
		}
		public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
			this.sslSocketFactory = sslSocketFactory;
		}
		public X509TrustManager getX509TrustManager() {
			return x509TrustManager;
		}
		public void setX509TrustManager(X509TrustManager x509TrustManager) {
			this.x509TrustManager = x509TrustManager;
		}
    }

    /**
     * 创建TSL环境（忽略Https校验）
     *
     * @return
     *
     * @author 延晓磊
     * @since 2024年08月21日
     */
    public static SSLContext createIgnoreContext() {
        try {
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new X509TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { }
                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { }
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());
            return context;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
